\section{Benchmark principal}
\label{sec:benchjdbccmp}

O benchmark consiste em criar um determinado número de threads e medir o tempo total que eles levam a executar a sua tarefa. A tarefa é atribuída no momento da criação dos threads e corresponde à execução de um contexto. 

Foram realizados testes nos contextos: \textbf{leitura}, \textbf{actualização}, \textbf{inserção} e \textbf{remoção}. O código executado para cada contexto encontra-se nas listagens \ref{lst:ctx-read} até \ref{lst:ctx-delete}. 

Estes contextos foram testados num cenário que tenta representar uma situação de utilização de um result set por vários threads. 
O cenário consiste em dividir logicamente um result set e atribuir uma gama de linhas a cada thread. Na sua execução, cada thread realiza a sua tarefa sobre as linhas lhe são destinadas. 
De notar que este é um cenário de vários possíveis.

\lstinputlisting[firstline=2,lastline=16,caption=Contexto de leitura.,label=lst:ctx-read]{code/contexts.java}

\lstinputlisting[firstline=19,lastline=35,caption=Contexto de actualização.,label=lst:ctx-update]{code/contexts.java}

\lstinputlisting[firstline=38,lastline=51,caption=Contexto de inserção.,label=lst:ctx-insert]{code/contexts.java}

\lstinputlisting[firstline=54,lastline=61,caption=Contexto de remoção.,label=lst:ctx-delete]{code/contexts.java}

A variável inteira \texttt{linesPerThread} possui o número de linhas atribuídas a cada thread, e o seu valor é atribuído directamente como parâmetro de teste. O número de linhas da tabela é igual ao número de linhas por thread multiplicado pelo número de threads.
A variável \texttt{counter} é uma instância da classe \emph{AtomicInteger} \cite{AINT2011}, e é-lhe atribuído o valor \texttt{1} no início de cada teste. A variável counter auxilia o processo de divisão do result set em gamas. Cada thread obtém o valor da variável, que corresponde ao número da primeira linha da gama, e calcula o valor do início da próxima gama. O valor do número da última linha da gama é calculado adicionando o número de linhas por thread ao valor da primeira linha da gama.

Foram realizados benchmarks com o driver da Microsoft (disponível em \cite{MSDriver}), com a solução \emph{ResulSet Wrapper} e a com solução \emph{Cursor}.

De modo a apresentar e discutir os resultados de modo mais sintético, utilizaram-se os seguintes nomes para identificar cada solução:
\begin{itemize}
  \item $MSJDBC$:     Teste usando o driver da Microsoft;
  \item $CJDBC_I$:  Teste usando o driver implementado, na versão com cache individual;
  \item $CJDBC_S$:  Teste usando o driver implementado, na versão com cache partilhado;
  \item $WJDBC$:    Teste usando o driver da Microsoft, na versão \emph{Wrapper};
\end{itemize}

O benchmark do $MSJDBC$ cria um result set para cada thread, porque o result set não pode ser correctamente partilhado pelas entidades concorrentes.
Para o benchmark do $WJDBC$ é criado um result set do driver da Microsoft que depois é partilhado entre os threads, e cada thread acede ao result set através de um \emph{wrapper}. 
Para os benchmarks do $CJDBC_I$ e $CJDBC_S$ é criado um cursor cliente do result set para cada thread.

O tipo de result set dos testes será sempre TYPE\_SCROLLABLE\_SENSITIVE.
Uma vez que um cursor \emph{forward-only} só permite percorrer o \gls{dataset} numa direcção, não é possível recuperar o contexto, nem existe a possibilidade de atribuir uma porção do dataset a cada thread, pois este não pode mover o result set para uma linha específica (a operação \texttt{absolute} não está disponível). 
A solução \emph{ResultSet Wrapper} tem como pedra basilar o restauro do contexto, e como já foi dito não é possível restaurar o contexto a não ser que o result set seja \emph{scrollable}; por estes motivos não são realizados testes com o tipo de result set TYPE\_FORWARD\_ONLY. No contexto da Leitura o tipo de concorrência do result set é CONCUR\_READ\_ONLY e nos contextos da Actualização, Inserção e Remoção a concorrência é do tipo CONCUR\_UPDATABLE.


Antes da execução propriamente dita do benchmark é necessário proceder à preparação da base de dados, pois alguns testes de desempenho necessitam que existam dados na tabela de testes. 

Todas as \gls{statement} utilizadas nos testes de desempenho para criar os result set foram realizadas sobre a tabela representada na Figura \ref{img:test-table}.

\begin{figure}[H]
  \caption{Tabela utilizada no benchmark.}
  \label{img:test-table}
  \centering
  \includegraphics[width=4.0cm]{images/database/test-table}
\end{figure}

As listagens \ref{lst:setupbdUD} e \ref{lst:setupbdI} apresentam os passos que são efectuados na preparação da base de dados dos testes de desempenho para os diferentes contextos.

Os contextos de Leitura, Actualização e Remoção limpam os dados da tabela, e introduzem novos dados antes de executar o benchmark. O contexto de Inserção só limpa os dados da tabela antes de executar o benchmark, já que a própria execução consiste em introduzir dados na tabela.

\begin{lstlisting}[texcl=true,caption={Preparação para executar os contextos de Leitura, Actualização e Remoção.},label={lst:setupbdUD}]
Limpar a tabela de testes
Introduzir novos valores na tabela de testes
Executar o benchmark
\end{lstlisting}

\begin{lstlisting}[texcl=true,caption={Preparação para executar o contexto de Inserção.},label={lst:setupbdI}]
Limpar a tabela de testes
Executar o benchmark
\end{lstlisting}

Na execução do benchmark são medidos dois tempos: \textbf{tempo de preparação} (fig. \ref{img:count-setup}), que corresponde ao tempo necessário para executar as \emph{queries} e criar os threads, e \textbf{tempo de execução} (fig. \ref{img:count-execution}), que corresponde ao tempo total que os threads criados levam a terminar a sua tarefa.

\begin{figure}[H]
  \caption{Medição do tempo de preparação}
  \label{img:count-setup}
  \centering
  \includegraphics[width=6.2cm]{images/benchmark/count-setup}
\end{figure}

\begin{figure}[H]
  \caption{Medição do tempo de execução}
  \label{img:count-execution}
  \centering
  \includegraphics[width=7.0cm]{images/benchmark/count-execution}
\end{figure}

Na inicialização de variáveis são criados os result set apropriados a cada situação e definidos parâmetros tais como o número de linhas por thread. Para o $MSJDBC$ neste passo não é criado algum result set, pois cada thread é que se encarrega de criar o seu próprio result set. Para o $WJDBC$ este passo também incluir criar a fábrica de cursores.

Na criação dos threads é atribuída uma tarefa (Runnable) a cada thread. A tarefa está relacionada com o contexto. Os threads no $MSJDBC$ criam agora o seu result set e os threads das restantes soluções obtêm o cursor cliente para o result set criado no passo anterior.
 
Os resultados deste benchmark são apresentados nas secções \ref{sec:resjdbccmp} e \ref{sec:reswjdbccmp}, e discutidos nas secções \ref{sec:disjdbccmp} e \ref{sec:diswjdbccmp}.
